说明:ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量
- 不再需要
UMD模块格式了,将来服务器和浏览器都会支持ES6模块格式。目前,通过各种工具库,其实已经做到了这一点。 - 将来浏览器的新API就能用模块格式提供,不再必要做成全局变量或者navigator对象的属性。
- 不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供。
| 两个命令 | 说明 |
|---|---|
export |
规定模块的对外接口 |
import |
引入其他模块提供的功能 |
适用比较:
| 模块加载方案 | 说明 |
|---|---|
| CommonJS | 用于服务器 |
| AMD | 用于浏览器 |
| es6 module | 浏览器和服务器通用的模块解决方案 |
注意:Node的默认模块格式是CommonJS,目前还没决定怎么支持ES6模块。所以,只能通过Babel这样的转码器,在Node里面使用ES6模块。
script
1 | <script type="module" src="foo.js"></script> |
import
1 | // ES6模块 |
1 严格模式
说明:ES6的模块自动采用严格模式,不管你有没有在模块头部加上use strict;
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用
with语句 - 不能对只读属性赋值,否则报错
- 不能使用前缀0表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量
delete prop,会报错,只能删除属性delete global[prop] eval不会在它的外层作用域引入变量eval和arguments不能被重新赋值arguments不会自动反映函数参数的变化- 不能使用
arguments.callee - 不能使用
arguments.caller - 禁止
this指向全局对象 - 不能使用
fn.caller和fn.arguments获取函数调用的堆栈 - 增加了保留字(比如
protected、static和interface)
2 export命令
说明:一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量
2.1 简单使用
变量
必须是声明表达式
1 | export var firstName = 'Michael'; |
字面量(推荐)
类似对象属性的简写方式,不同点在于可以使用 as 重命名对外接口
1 | var firstName = 'Michael'; |
函数或类
1 | export function multiply(x, y) { |
2.2 注意点
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系
错误写法
1 | // 报错 |
正确写法
1 | // 写法一 |
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
1 | export var foo = 'bar'; |
export命令可以出现在模块的任何位置,只要处于模块顶层就可以(如果处于块级作用域内,就会报错)
1 | function foo() { |
3 import命令
说明:使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)
3.1 基本使用
说明:import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名
- 大括号里面的变量名,必须与被导入模块对外接口的名称相同
- 如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名
import命令具有提升效果,会提升到整个模块的头部,首先执行- 如果在一个模块之中,先输入后输出同一个模块,
import语句可以与export语句写在一起(不推荐,可读性不好)
扩展:ES7有一个提案,简化先输入后输出的写法,拿掉输出时的大括号
技巧:import语句会执行所加载的模块,可以只执行不输入
1 | /* 如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名 */ |
4 模块的整体加载
说明:除了指定加载某个输出值,还可以使用整体加载,即用星号*指定一个对象,所有输出值都加载在这个对象上面。
1 | import * as circle from './circle'; |
5 export default 命令
用途:为模块指定默认输出
- 可以在一条
import语句中,同时输入默认方法和其他变量 - 因为
export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句 - 一个模块只能有一个默认输出,因此
export deault命令只能使用一次
原理:本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字
1 | /* 本质上,`export default`就是输出一个叫做`default`的变量或方法,然后系统允许你为它取任意名字 */ |
6 模块的继承
说明:模块之间也可以继承
注意:export *命令会忽略circle模块的default方法
1 | export * from 'circle'; |
7 ES6模块加载的实质
说明:ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
ES6输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错(但如果变量是对象,可以修改添加其内容,类似const)- 不同的脚本加载同一个模块,得到的都是同样的实例
8 循环加载
说明:对于JavaScript语言来说,目前最常见的两种模块格式CommonJS和ES6,处理“循环加载”的方法是不一样的,返回的结果也不一样。
8.1 CommonJS模块的加载原理
说明:CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
8.2 CommonJS模块的循环加载
说明:CommonJS模块的重要特性是加载时执行,即脚本代码在require的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。
8.3 ES6模块的循环加载
说明:ES6模块是动态引用,如果使用import从一个模块加载变量(即import foo from 'foo'),那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。
9 跨模块常量
说明:其实就是将普通的const常量封装到一个公共模块,暴露给其它模块来使用。
1 | // constants.js 模块 |
10 ES6模块的转码
10.1 ES6 module transpiler
说明:ES6 module transpiler是square公司开源的一个转码器,可以将ES6模块转为CommonJS模块或AMD模块的写法,从而在浏览器中使用。
| 参数 | 说明 |
|---|---|
| -o | 指定转码后的文件名 |
1 | # 安装 |
10.2 SystemJS
用途:一个垫片库(polyfill),可以在浏览器内加载ES6模块、AMD模块和CommonJS模块,将其转为ES5格式
说明:它在后台调用的是Google的Traceur转码器
app/es6-file.js:定义模块
1 | export class q { |
引用&使用模块
1 | <script src="app/es6-file.js"></script> |